package com.example.demo.service;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private final WebSocketQueue webSocketQueue;

    /**
     * 存储在 Channel 中的 attr 属性名（存储用户Id）
     */
    public static final String USER_ID = "userId";

    public WebSocketHandler(WebSocketQueue webSocketQueue) {
        this.webSocketQueue = webSocketQueue;
    }

    /**
     * 在新的 channel 被添加到 channelpipeline 中被调用。通常发生在连接建立时，即 channel 已经被成功绑定并注册到 EventLoop 中
     * 在连接建立时被调用一次
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        if (NettyConfig.getOnlineChannelGroup().size() >= 2) {
            webSocketQueue.addToQueue(channel);
            log.info("queue: {}", webSocketQueue.getQueueSize());
        } else {
            //将新链接的客户端channel存储
            log.info("连接建立成功");
            NettyConfig.getOnlineChannelGroup().add(channel);
            log.info("当前在线用户数量：{}", NettyConfig.getOnlineChannelGroup().size());
        }
        super.handlerAdded(ctx);
    }

    /**
     * 在 websocket 连接断开时，netty 会触发 channelInactive 事件，并将事件交给事件处理器进行处理
     * 在 channelInactive 事件处理过程中，会调用 handlerRemoved 方法，用于进行一些资源释放等操作，确保 WebSocket 连接正常断开。
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        cleanChannel(channel);
        log.info("客户端断开链接 --> {}，在线用户数量：{}", channel.id(), NettyConfig.getOnlineChannelGroup().size());
    }

    /**
     * 处理客户端非正常断开
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //获取断开连接的客户端channel
        Channel channel = ctx.channel();
        cleanChannel(channel);
        log.info("客户端异常断开 --> {}，在线用户数量：{}", channel.id(), NettyConfig.getOnlineChannelGroup().size());
        //当发生异常时，手动关闭Channel
        channel.close();
    }

    /**
     * 删除连接相关的数据
     *
     * @param channel
     */
    private void cleanChannel(Channel channel) {
        //获取客户端 channel 中存储的名为 userId 的 Attribute
        Attribute<String> userIdKey = channel.attr(AttributeKey.valueOf(USER_ID));
        String userId = userIdKey.get();
        //从 channelGroup 中移除断开的 channel
        NettyConfig.getOnlineChannelGroup().remove(channel);
//        //从 map 中移除 user 和 channel 的映射
//        NettyConfig.getOnlineUserChannelMap().remove(userId);
//
//        //通知所有用户某用户下线了
//        NettyConfig.getOnlineChannelGroup().writeAndFlush(new TextWebSocketFrame("用户" + userId + "下线了"));

    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {

        //接收到的文本信息
        String text = msg.text();
        ctx.channel().writeAndFlush(new TextWebSocketFrame("Server: " + text));
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //将新的websocket连接加入队列
//        webSocketQueue.addToQueue(ctx.channel());
//        log.info("New client connected: {}", ctx.channel().remoteAddress());
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //移除连接
        log.info("Client disconnected: {}",ctx.channel().remoteAddress());;
        super.channelInactive(ctx);
    }
}
